package com.example.redis6.controller;

import com.example.redis6.util.JsonData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


/**
 * description: CouponController <br>
 * date: 2021/7/20 14:35 <br>
 *
 * @author: ZhangYixin <br>
 * version: 1.0 <br>
 */
@RestController
@RequestMapping("/api/v1/coupon")
public class CouponController {

    @Autowired
    private StringRedisTemplate redisTemplate;


    @GetMapping("add")
    public JsonData saveCoupon(@RequestParam(value = "couponId",required = true) int couponId){
        lock(couponId);
        return JsonData.buildSuccess();
    }

    private void lock (int couponId){
        // 防止其他线程误删
        String uuid = UUID.randomUUID().toString();

        String lockKey = "lock:coupon:"+couponId;

        String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";

        Boolean isSet = redisTemplate.opsForValue().setIfAbsent(lockKey, uuid, Duration.ofSeconds(30));

        System.out.println(uuid+"加锁状态："+isSet);

        if (isSet) {
            // 加锁成功
            try {
                // todo 业务处理
                TimeUnit.MILLISECONDS.sleep(10000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                Object execute = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(lockKey), uuid);
                System.out.println("解锁状态："+execute);
            }

        }else {
            // 自旋操作
            // 加锁失败
            try {
                System.out.println("加锁失败");
                TimeUnit.MILLISECONDS.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 失败之后过一段时间 再尝试获取锁
            lock(couponId);
        }
    }

}
